package lol.clann.minecraft.springboot.plugin.bukkit.config.jackson;

import relocate.com.fasterxml.jackson.core.JsonParser;
import relocate.com.fasterxml.jackson.core.JsonProcessingException;
import relocate.com.fasterxml.jackson.databind.DeserializationContext;
import relocate.com.fasterxml.jackson.databind.JsonDeserializer;
import relocate.com.fasterxml.jackson.databind.JsonNode;
import relocate.com.fasterxml.jackson.databind.ObjectMapper;
import relocate.com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.auto.service.AutoService;
import lol.clann.minecraft.springboot.api.bukkit.constant.NBTTypeEnum;
import lol.clann.minecraft.springboot.api.bukkit.exception.NBTException;
import lol.clann.minecraft.springboot.api.bukkit.utils.NBTUtils;
import lol.clann.minecraft.springboot.api.context.SpringContext;
import lol.clann.minecraft.springboot.api.model.LazyField;
import lol.clann.minecraft.springboot.api.model.reflect.FieldInvoker;
import lol.clann.minecraft.springboot.api.spi.jackson.JacksonDeserializer;
import lol.clann.minecraft.springboot.bukkit.utils.NMSClasses;
import lol.clann.minecraft.springboot.bukkit.utils.NMSReflectUtils;

import java.io.IOException;
import java.util.List;

/**
 *
 * @author pyz
 * @date 2019/5/18 2:56 PM
 */
@AutoService(JacksonDeserializer.class)
public class NBTTagListDeserializer extends JsonDeserializer<Object> implements JacksonDeserializer {

    private LazyField<NBTUtils> nbtUtils = LazyField.of(() -> SpringContext.getBean(NBTUtils.class));
    private LazyField<ObjectMapper> objectMapper = LazyField.of(() -> SpringContext.getBean(ObjectMapper.class));
    private static FieldInvoker type;

    static {
        type = new FieldInvoker(NMSReflectUtils.getField(NMSClasses.getNBTTagList(), "type"));
    }

    @Override
    public Class getType() {
        return NMSClasses.getNBTTagList();
    }

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        Object tagList = nbtUtils.get().newNBTTagList();
        List tagListValue = nbtUtils.get().getValue(tagList);
        ArrayNode arr = objectMapper.get().readTree(p);
        byte type = 0;
        for (JsonNode jsonNode : arr) {
            if (jsonNode.isObject()) {
                type = 10;
                tagListValue.add(objectMapper.get().readValue(jsonNode.traverse(), NMSClasses.getNBTTagCompound()));
            } else if (jsonNode.isArray()) {
                type = 9;
                tagListValue.add(objectMapper.get().readValue(jsonNode.traverse(), NMSClasses.getNBTTagList()));
            } else {
                String content = jsonNode.asText();
                String identity = content.substring(0, 2);
                NBTTypeEnum nbtType = NBTTypeEnum.getByIdentity(identity);
                if (nbtType == null) {
                    throw new NBTException("can not resolve nbt value:" + content);
                }
                if (nbtType == NBTTypeEnum.NBTTagCompound) {
                    type = 10;
                } else {
                    type = 8;
                }
                Object v = objectMapper.get().convertValue(content.substring(2), nbtType.getField().getField().getType());
                Object tagV = nbtType.getConstructor().invoke(null);
                nbtType.getField().set(tagV, v);
                tagListValue.add(tagV);
            }
        }
        NBTTagListDeserializer.type.set(tagList, type);
        return tagList;
    }

}

